#include <iostream>
#include <string>
#include <exception>
#include <thread>

#include <cstring>
#include <cstdlib>

#ifdef _WIN32
#include <WinSock2.h>
#include <Windows.h>

#pragma comment(lib, "ws2_32.lib")
#pragma warning(disable: 4996)

#elif defined(__linux__)
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#endif

#ifdef _WIN32
class win_socket
{
	typedef win_socket self;
private:
	// windows下套接字初始化,设定为单例
	win_socket()
	{
		WSADATA wsd;
		WSAStartup(MAKEWORD(2, 2), &wsd);
	}
	win_socket(const self&) = delete;
	self& operator=(const self&) = delete;
	~win_socket()
	{
		WSACleanup();
	}
public:
	static win_socket _instance_central_cache;	// 单例对象(饿汉)
};
// 单例对象创建
win_socket win_socket::_instance_central_cache;
#endif

class Socket
{
public:
#ifdef _WIN32
	typedef SOCKET Socket_t;
#elif defined(__linux__) 
	typedef int Socket_t;
#endif

	enum socket_type
	{
		TCP = SOCK_STREAM,
		UDP = SOCK_DGRAM
	};
public:
	// 创建套接字
	static Socket_t get_socket(int type)
	{
		Socket_t sockfd = socket(AF_INET, type, 0);
		if (sockfd < 0)
			throw std::runtime_error("create socket error");
		return sockfd;
	}
	// 设置sockaddr
	static int set_socketaddr(struct sockaddr_in& addr, const std::string& ip, int port)
	{
		memset(&addr, 0, sizeof(addr));
		addr.sin_family = AF_INET;
		addr.sin_port = htons(port);
		addr.sin_addr.s_addr = inet_addr(ip.c_str());
		return sizeof(addr);
	}
	static int set_socketaddr(struct sockaddr_in& addr, unsigned long ip, int port)
	{
		memset(&addr, 0, sizeof(addr));
		addr.sin_family = AF_INET;
		addr.sin_port = htons(port);
		addr.sin_addr.s_addr = ip;
		return sizeof(addr);
	}
	// tcp连接
	class tcp
	{
	public:
		static int connect_server(Socket_t sockfd, struct sockaddr_in& server, int len)
		{
			if (connect(sockfd, (const sockaddr*)&server, len) < 0)
				throw std::runtime_error("connect error");
			return sockfd;
		}
	};
	static void destroy_socket(Socket_t sockfd)
	{
#ifdef _WIN32
		closesocket(sockfd);
#elif defined(__linux__) 
		close(sockfd);
#endif
	}
};

void get_message(const std::string& server_ip, const uint16_t server_port)
{
	// 配置服务器sockaddr_in
	struct sockaddr_in server;
	int len = Socket::set_socketaddr(server, server_ip, server_port);

	// 创建套接字
	Socket::Socket_t sockfd = Socket::get_socket(Socket::TCP);
	Socket::tcp::connect_server(sockfd, server, sizeof(server));

	while (true)
	{
		char choice = 0;
		// 输入y刷新数据,n退出
		std::cout << "refresh ? (y / n)" << std::endl;
		std::cin >> choice;
		if (choice == 'n')
			break;

		// 向服务器发送数据
		const char send_message[] = { "get" };
		send(sockfd, send_message, sizeof(send_message), 0);

		// 从服务器接收数据
		constexpr size_t recieve_size = 1024;
		char buffer[recieve_size] = { 0 };
		int n = recv(sockfd, buffer, recieve_size - 1, 0);
		if (n < 0)
		{
			printf("recvfrom error, errno: %d, err string: %s", errno, strerror(errno));
			continue;
		}
		buffer[n] = 0;
		std::cout << "---------------------------------------------------------------------------------------------------" << std::endl;;
		std::cout << buffer << std::endl;
	}
	std::cout << "over" << std::endl;
}

int main()
{
	// 服务器IP 端口号
	uint16_t server_port = 8083;
	std::string server_ip = "49.235.120.243";

	std::cin >> server_ip >> server_port;

	get_message(server_ip, server_port);

	return 0;
}